Phase 7 — Wiki UX
Arc started 2026-07-22, after Phase 6. Sections are Roman numerals
and steps within them are lettered; each step's title says what it does,
followed by a sentence on what was proposed and, once worked, a few on what
was done and anything learned. Marker legend:
▶ being worked on,
⚑ implemented and waiting to be reviewed,
✓ done,
✓✗
closed by deciding not to do it, ? open decision,
unmarked = planned.
What this arc is for
The wiki is where a group keeps its shared pages, so its editing and
resource surfaces are what a group touches most. This arc finishes the
page-resource folder UI (I), gives the editor a live preview and then a
markup toolbar (II), makes the category mechanism a real content tool (III),
completes the email witness flow for secret ballots (IV), and documents the
folder UI once it is finished (V).
- ✓ Finish the page-resource folder
UI. The folder is what a group touches most, so it is finished
first.
- ✓ The page-resource folder reflows
as a card grid. A fixed table with four hard column widths gave
the folder a 502px floor. The grid is sized by a container query on the
folder itself.
- ✓ Rows in the folder can be picked
and acted on together. Rows are picked in the browser. Nothing
is sent until an action is asked for.
- Give the editor a preview and then an assist. The preview
comes first, since the toolbar shows its result.
- ✓ A wiki page shows a live preview
beside its source. It renders in the browser through the
existing parser port, so typing costs no request.
- ✓ The two panes share one
window. It is of settled height and split by a draggable
bar. Under 52rem the preview sits above the source.
- ✓ The preview opens from a book
icon and starts closed. A page that is never previewed pays
nothing for the feature.
- ✓ Picking words out in either pane
marks them in the other. They are brought into view. The
pane being worked in never moves.
- ✓ Charts, tables, math and search
boxes all draw in the preview. Each is rendered from what
the markup carries, so nothing is fetched.
- ✓ A resource shown as an example
is not drawn. Text inside nowiki is left as itself, in both
parsers.
- ✓ Buttons insert wiki markup at
the cursor. The textarea stays the source of truth and the
preview shows the result.
- ✓ The preview follows what a
button puts in. A browser raises nothing when a script
writes into a field, so the preview went on showing what stood
there before the markup was added.
- ✓ What a button puts in can be
taken back with the undo key. The whole field had been
rewritten, which throws away what the browser remembers of the
writing; the words now go in the way typing puts them in.
- ✓ A picture stored with a page
now shows in the preview. The preview asks the site for
such a picture by group and page, and it was asking with both of
those set to zero, so the site had nothing to look up and the
picture came out broken. The page being edited knows its group
and its own id, so both are written onto the editing field as
data attributes and the preview reads them from there.
- ▶ Make the category mechanism a
real content tool, so a group can run as a newsroom. A wiki page
becomes an article, other pages front those articles, and a category is
what ties the two together. Today a journalist types the icon, the
open-graph properties and each category tag by hand, in two places, with
nothing checking the spelling. The five steps below remove that typing and
make a category something the site knows about rather than a string in a
body. To-do item 20.
- ⚑ A front page collects articles
into a shape a writer chooses. Such a page is laid out by
picking a shape and naming what fills each of its places, rather than
by typing tags. What is saved is ordinary wiki markup, so anyone can
read or edit the page without the form.
- ⚑ Four shapes are offered, each
drawn as a thumbnail. A writer picks by the look of it: a
lead story with headlines beneath, a row of cards, a grid of four,
and stacked sections. The shapes and their places appear as soon as
the kind is chosen rather than after a save.
- ⚑ Each place says what it
holds. A lead holds an article and the headlines beneath
hold a category, so neither asks; anywhere else offers the choice,
then a page to name or a category to pick from the group's
list.
- ⚑ The settings show what belongs
to the kind of page being made. Every kind showed every
control, so an alias page offered a border and a front page offered
a resource path. One table says which parts each kind uses, the
form follows it as the kind is chosen, and the settings offer
saving alone.
- ⚑ One of a set of buttons stands
for the whole set when a form is sent. Every button was
being sent, so the last of them stood for the choice whichever a
person had picked.
- ⚑ The shapes are given the
styling that makes them look like themselves. Cards lay
along a line and wrap, the grid is two across and one on a narrow
window, sections stack with a rule between, and headlines under a
lead are a plain run of names. The elements a list is made of are
each told how to lay themselves out, since a browser lays an
unknown element along the line like a word.
- ⚑ A list of what is filed under
a name draws at all. The parser left the words asking for
a list as words, while the site looked for a mark those words
never became, so no list had ever drawn. The parser leaves that
mark now.
- ✓ A group knows its own
categories and what its pages are for. Everything after this
leans on the group's list existing, since a chooser can only offer
what the group knows.
- ✓ A group's settings hold the
names its pages may be filed under. Each name stands on
its own row with a mark that drops it. A field below adds
another, the way a domain is added on the servers page. A name
already standing, or one holding a comma, is passed over. What
is sent is still one line with commas between, kept in a hidden
field and rebuilt as rows come and go. A front page's category
pickers offer these alongside any name the group's pages are
already filed under.
- ✓ A group says what kind of
page a new page starts as. A newsroom sets it to news
article, so every page a journalist creates begins as one. A page
that already exists keeps the kind it was saved with. The
setting is labeled for what it holds rather than for what it
does. Its name and the categories' name each carried a colon
the markup supplies, so both read with two.
- ✓ A wiki page can be a news
article. A new page kind carrying what an article needs
and nothing else. The two new group settings live in columns of
their own, added by a version step so a database already in use
moves forward. Naming the columns in the seeding inserts keeps
them working when another column is added.
- A journalist writes a news article without leaving the
editing screen. Writing one today means filling in the
settings panel for the title, the author, the thumbnail and the
description, going back to the body to type the category tags, and
then typing the open graph properties by hand. All of that moves
onto the editing screen, and saving fills in the rest.
- ⚑ The title, author,
thumbnail and abstract sit above the writing area.
They are the first things a journalist needs and were three
clicks away in the settings panel. The four are moved out of
that panel onto the editing screen rather than drawn a second
time, so no field is asked for twice. The description is
labeled Abstract and the icon Thumbnail while a news article
is being written.
- ⚑ Categories are chosen
from a list beneath the abstract. They had to be typed
as tags in the body, where a misspelling filed the page
nowhere. The group's own names are offered, and a name chosen
stands as a row with a mark to drop it. What a page is already
filed under is read from its body, so opening one shows what is
there.
- ⚑ Saving writes the tags,
the head and the open graph properties. A journalist
should not have to write the
same category in three places, nor know what an open graph
property is. Saving writes the category tags into the body, so
searching by category still finds the page; puts the title,
author, thumbnail and abstract into the page's head; and writes
og:title, og:description, og:image, og:url and a property for
each category. The tag also files the page under that
category, which is a link from the page to itself carrying
the category's name.
- ⚑ A reader can see which
sections an article is in and follow them. Nothing on
a finished article said what it was filed under, so a reader
wanting more of the same had nowhere to go. The names stand
under the article's last words, each a link to the list of
what else is filed there.
- ⚑ A category list becomes a
real listing. A page drawing a category could ask only for
a name and a class. It can now say how many, in what order and
which page of them, the list it draws is ordinary markup, and a
category has a page of its own to lead to.
- ⚑ A list takes named
settings. How many to show, in what order, and how to
style them, given by name rather than by position, and any of
them may be left out. A list written as a bare set of classes
still reads, so pages already written go on working.
- ⚑ A long list offers the
rest. A front page showing one section of a busy group
gave a reader the first few and no way past them. Where more
are filed than were asked for, a line beneath the list says how
many there are and leads to all of them.
- ⚑ A category has a page of
its own. Asking for a category gives a page naming it
and listing what is filed under it, built as it is asked for
rather than kept, so a category has one from the moment
anything is filed under it. Every link to a category leads
there: the tags beneath an article and the way on beneath a
listing.
- ⚑ The list a category
becomes is ordinary markup. It had been tags of our
own invention, which carry a name but no meaning, so nothing
reading the page for someone could tell it was a list of
links. It is now a list of links.
- A category can reach another group, and the forms are written
up. A front page in one group collects articles filed in
another, written the way the site already writes a page in another
group. Planned.
- A category may name another group. Planned.
- The forms that reach another group are checked in both
routes. A link written that way works on the site and in
the preview alike. A file named that way works in neither today,
so that is new work rather than a regression to guard.
Planned.
- The category forms are written up on the syntax page.
Neither the tag nor the list appears there today. Delivered as wiki
help source in a text file, since that page is generated.
Planned.
- Let named witnesses take part in a secret ballot by email.
The asynchronous flow lets them answer in their own time rather than all at
once. To-do item 21. Planned.
- Document the wiki resource-folder interface. It is written
as wiki help source and delivered as a text file. Best done after the folder
itself. To-do item 37. Planned.
- Other work accomplished, oldest first. Each step below was
reached while working on something else.
- ✓ Git clone, push and pull work
over HTTP against a Yioop repository. The smart protocol now
works over both HTTP/1.1 and HTTP/2.
- ✓ Packfiles are built on a
fiber. The server answers other requests while one is
built.
- ✓ Negotiation settles.
The server names a commit both sides share, so a client with a long
history stops asking.
- ✓ A reply states its length and
streams. A deferred reply sends only its buffered body,
which claimed a length it did not send.
- ✓ Only what the client lacks is
sent. Objects go as deltas against what it holds. A new
GitDelta writes and reads that format on bytes.
- ✓ A deep clone of the live
repository completes. It stopped partway before, with a
differing amount delivered each time.
- ✓ A running Yioop keeps its memory
bounded. Both servers were made to say where their memory went,
and then to use less of it.
- ✓ The web server reports its own
memory. The request that finally fails is no longer the one
blamed.
- ✓ The mail server reports its own
memory. It had gone from 120MB to its 1GB limit in ten
seconds with nothing said.
- ✓ A mail server fatal names what
it was doing. It gives the account, the folder and the full
command, where it named only the bare verb.
- ✓ Mail folder indexes are held as
plain values. The same folder costs 6MB where it cost 48MB.
The cache is bounded by records rather than folder count.
- ✓ A web session lives in a file
rather than in memory. What the server keeps is the time
and use-count. A session past the request-size limit is
refused.
- ✓ Every page fits its own
window. A minimum width on the body container meant pages
overflowed between about 601 and 1060 pixels. An activity that is mostly
working area now takes the window's width.
- ✓ A missing wiki page no longer
leaves nulls in the media path. One request raised a warning, a
deprecation and a second warning, all from the same defect.
- ✓ A visitor can report an issue
without an account. The tracker is public to read, so someone
who hits a bug no longer has to register or stay silent.
- ✓ A report is held for an
editor. There is a queue with bulk discard. A reporter may
be barred for a week, a month or for good.
- ✓ Each repository chooses its own
setting. It is none, moderated or unmoderated, defaulting
to moderated.
- ✓ Issue lists are read by
scrolling. Reaching the end fetches the next page as rows.
That needed a stable sort order and an allowed offset field.
- ✓ Yioop no longer needs three
outside programs. qrencode, image magick and calibre were each
required for one small thing.
- ✓ Yioop draws its own code
symbols. The same arithmetic is written in PHP and in the
browser. A test compares the two square by square.
- ✓ Each kind of file makes its own
thumbnail. A document, a book and a text file each do their
own, in the processor that owns them.
- ✓ Audio messages are transcribed
in the browser. The browser listens while a message is
recorded. The server keeps nothing beside the recording.
- ✓ A recording can become its
words before sending. A button beside play and
delete replaces the recording with what was heard. The text
can be edited and is sent as an ordinary message.
- ✓ A recording sent as audio
carries its words inside the message. They are its
resource description. The pipe and doubled parenthesis are
taken out so the words cannot end the markup early.
- ✓ The reader's browser draws
a toggle that shows the words. It reads them off the
page itself, so the click costs no request. Fresh pushed
messages get their toggles the same way.
- ✓ The send guard resets when
a message is sent. It was set once and never let
go, so a second message on the same page load was silently
held.
- ✓ A document thumbnail shows its
front page. It reads that page alone, rather than the whole
document.
- ✓ The page tree is followed to
find the first page. That includes reaching through the
packed bundles a document may keep its objects in.
- ✓ A picture written in the four
colors ink uses is read. It is taken apart here, since
PHP's own reader returns it as all zeros.
- ✓ The page's words are drawn where
the page has them. They take the size and color it set,
with nothing behind them. Their place is the frame in force when the
text began.
- ✓ Shapes the page fills are drawn
too. That is how a nameplate set as an outline appears
rather than being lost.
- ✓ A document with a font in it
gives up its words. The going back to reading words was
compared rather than set. Everything after the first font was
skipped.
- ✓ A message with a recording
sends once and plays on both sides. Sending a recording
raised an error and left broken copies, as many as ten. Two halves,
both from this afternoon's commits, measured over HTTP/2 against the
secure server with a real microphone.
- ✓ The lost helper is
restored. The GroupModel rewrite dropped
linkResourceFolders while newMessage still called it. The Error
escaped the route, so the stream was never answered, and the
browser resent the same body each time.
- ✓ The route accepts the bare
token the renderer writes. The renderer had been changed
to put the token value alone in a recording's address. The route
still demanded name=value or a dash, so every read was turned
away to the error page.
- ✓ Opening a conversation no
longer answers itself with the whole conversation. Every
page load sent a call-ended signal, and the reply to it carried
the whole conversation back, some six hundred kilobytes a time.
Nothing read that reply. Three changes together took the cost to
eleven bytes.
- ✓ Ending is only said when a
call was in progress. Leaving a page said a call
had ended whether or not one had begun.
- ✓ The event body is read from
where the atto server puts it. It had been read
from the stream the server leaves empty, so every signal
looked like nothing at all.
- ✓ A call signal is answered
with a small acknowledgment. The sender never reads
the reply, so a page is the wrong thing to send back.
- ✓ A sent message carries no
unnamed parts. Buttons with no name went up with
every message and were dropped on arrival.
- ✓ A conversation's live channel
rides HTTP/2 and sends only new messages. The channel
had to fall back to an older connection, and each push carried
the whole conversation. It now rides the connection the page
already has, and a push is about seven hundred bytes.
- ✓ The server offers WebSockets
over HTTP/2. It advertises the extended connect
setting and accepts the connect that follows, so a socket
shares the page's own connection.
- ✓ An outbound frame is split to
the maximum data-frame size. A frame larger than
that broke the connection's framing.
- ✓ A push sends the conversation
list alone. It had rendered the whole page, so
every push carried the chrome around the messages.
- ✓ Control frames answered on a
socket keep the connection's framing. A close echo
written raw corrupted the stream carrying it.
- ✓ A carrier stream is let go
when its socket closes. It had been held until the
stream itself ended, which need never happen.
- ✓ A connection carrying a
socket still pumps what is waiting. It took a path
meant for sockets alone, and a large reply hung.
- ✓ A conversation lets go of its
channels when the browser leaves the page. Safari
otherwise reported the socket closed by suspension.
- ✓ A socket is handed what
opened it, and touches nothing else of the request.
The query and cookies had been put in the arrays an ordinary
request uses, where a finished response writes the session
named among them.
- ✓ How a socket's frames are
written is held in place by tests. Seven cases cover
the splitting, the wrapping and the drain path.
- ✓ A conversation and its
contacts can be let go of, in whole or in part. Only the
person who wrote a message could remove it, and there was no way
to clear a conversation or drop a contact. Each person now
manages their own half, and the other keeps theirs.
- ✓ Any message in one's own half
can be taken off it, whoever wrote it. A message is
kept twice, once in each person's group, and only the writer
could remove one.
- ✓ A whole conversation can be
let go. Only that person's copies go; the two remain
contacts with an empty conversation between them.
- ✓ A contact can be removed from
one's own list. Their messages go from this side,
along with the row the conversation hung from.
- ✓ A contact's row carries three
marks that open what can be done. The marks stand at
the end of the row and open a list of the two.
- ✓ The marks are drawn rather
than written as a letter. The letter for them is
missing from some of the faces a browser has.
- ✓ The row lays its parts out
along a line. It had been a plain block, so the
marks dropped below the row.
- ✓ The words in the list stand
in the ordinary flow. The rule placing a
contact's name by hand had squashed them.
- ✓ The message box fills the
width of its panel. A stray closing tag had left the
conversation drawn in three panels.
- ✓ A recording is made in one
kind every browser can play. Each browser writes its own
kind and none writes the same one, so a recording made in one
played nowhere else. The site now makes every recording over into
one kind, written one way.
- ✓ The kind asked for is the one
the most browsers play. mp4 and mp3 are asked for
under every name they go by, by building a recorder with each
rather than asking whether it is supported.
- ✓ A recording that already
arrives in the wanted kind is made over as well. Two
browsers writing the same kind do not write it alike.
- ✓ Recording is not offered
where the site cannot make one over. Without FFMPEG
a recording made in one browser could not be played in
another.
- ✓ A recording carries the mark
for its words in the lower corner. It had sat at the
top left, over the play controls.
- ✓ A recording with no words
carries no description, and one is still a recording.
It had been given a description naming its own file, and a
resource with none was left in the message as plain text.
- ✓ A browser that will not listen
is not offered the button that asks it to. Only a
plain refusal counts as one, since a browser that heard
nothing says so with other words.
- ✓ Signing out works
again. A browser was told the sign-out address had moved
for good, so it went straight to where it had been sent once and
never signed anyone out again.
- ✓ Being sent on is no longer
announced as a move for good. A reply carrying only
a Location header was answered as moved permanently.
- ✓ Signing out empties the
request rather than doing away with it. This server
keeps its process between requests.
- ✓ A failure while a request is
handled can be let out rather than caught. Caught,
only that connection is let go and the request answers with
nothing, which gives little away.
- ✓ A wiki page being read names
itself on its body. A domain's own stylesheet can reach
reading alone, and reach one group or one page within it, without
reaching the rest of the site.
- ✓ The three classes are
read-wiki, the group's name and the page's name.
Spaces and underscores become hyphens and anything a class
cannot carry is dropped.
- ✓ A wiki page served as a
static page carries the same classes. The group
named is the one the domain routes to, so two domains give
two different group classes.
- ✓ The class for acting as
someone else is gone, along with the rules that waited on
it. The name the body looked at was never set
anywhere.
- ✓ Searching a mail folder lets
go of each message once it has been read. The reader
that walks a search's terms names itself, and a thing that names
itself is not let go when the count of what points at it drops.
It held each message body, so a search over a large folder ran
the mail server out of memory.
- ✓ Tests are kept one class to a
file and write under the test files. Cases had been
spread across narrow files of their own, and one wrote its
scratch work into the work directory.
- ✓ A page keeps itself while it
is being written. A writer no longer has to remember to
save. The page saves itself once they stop typing, and the
controls for saving by hand step aside while it does.
- ✓ A control beside the editor's
other buttons turns the keeping on and off. It is
two arrows going round, drawn rather than written. Green says
the page is keeping itself, red with a line across says it is
not, and the word Saving stands beside it while a save goes.
- ✓ Five quiet seconds after a
change the page is saved. Nothing further is saved
until another change is made. Such a save gives its own
reason, so the history reads properly.
- ✓ The controls for saving by
hand step aside while the page keeps itself. The
reason for an edit, the save button and the way to see the
page are left out. A page's settings are a form to fill in
and send, so they keep their save button and are never
offered the keeping.
- ✓ Each save takes the fresh
mark the site sends back. A save whose mark is older
than the page's last change is refused. Without this the
first save of a sitting landed and every one after was turned
away.
- ✓ A file dropped into the
writing area is sent at once. Its name went into the
page while the file waited for a press of save that never
came. The writer stays where they were while it goes, and the
count of how much has gone up is cleared when it lands.
- ✓ A page written for the first
time learns its own name. Such a page has no id
until it is saved, and a page that saves itself never
reloads. The id is taken from what the site sends back, so
the preview can ask for the files kept with it.
- ✓ The preview reads a page the
way the site will. A writer sees what a reader will see
rather than an approximation. Each piece was built by rendering
samples through the site and matching them.
- ✓ A page written in markdown
has a preview of its own. There was a reader for
wiki markup and none for markdown. The new one covers words,
headings of both kinds, lists, quotations, rules, code,
tables, links, notes and the marks that work within a
line.
- ✓ Both readers take the
templates that name a class, an id or a style. Only
the plain names were read, so a page using the block forms
lost its wrapping. A template laid out over several lines is
read too, on the site as well as in the browser.
- ✓ A block written with quotes
reads the same after a save. Text is cleaned on its
way in, and cleaning turns a quote into the name standing for
it. Both marks now open a value, so a block survives the
round trip.
- ✓ Both previews draw the fields
of a form. A page showed the words asking for a
field rather than the field. One drawer serves both readers
and covers every kind the site knows.
- ✓ A form looks as it will to a
reader. The site leaves standing-in marks and fills
them when it draws a page, so the preview showed them as
words. A fresh form now comes up empty, and the date rides
along without being shown.
- ✓ A list carries its choices
and a field keeps the words after it. A list takes
its choices from a block named beside it, which the preview
never copied. A field followed by anything on the same line
was left unread.
- ✓ The preview is dressed the
way a reader will see the page. It carries the same
three classes a page being read carries. A domain's own
stylesheet reaches what the writer is looking at.
- ✓ Files kept with a page draw
in the preview. A picture, a document or a recording
named on a page shows as itself. The address it is asked for at
is built the way the site builds it.
- ✓ A file is asked for the way
the site serves it. Where the site serves pretty
addresses it serves a file as a path rather than a query.
The address is rooted at the site, since a path read against
the page points under that page.
- ✓ A file is asked for under the
mark the site would use. A file belonging to the
public group, or to any group anyone may join, is asked for
under a row of zeros. The page works this out as the site
does and tells the preview.
- ✓ Every kind of picture the
site serves is drawn. The list of picture endings
was written before webp and the kinds that followed it. A
picture asked for without a link is drawn on its own, and a
document is shown in a frame.
- ✓ A file asked for as a thumb
draws the small picture kept beside it. The reader
drew the file itself, which for a document meant a bare link.
The site draws it the same way now, and neither points at a
picture that was never made.
- ✓ A file named inside a table
cell stays whole. Such a naming carries a bar of its
own, and a bar ends a cell. The reader follows the depth of a
naming as it already followed a link's.
- ✓ A file added to a page is
described with a space before its name. The word and
the name ran together.
- ✓ A page carries its locale
wherever it goes. A writer works on a page in one
language while reading the site in another. Every way of looking
at the page stays in the language being worked on.
- ✓ A writer chooses which locale
a page is written in. The locale above the editor
was a word; it is a choice now. Choosing another goes to that
locale's page, so what is saved after goes there.
- ✓ The locale goes with every
way of looking at a page. Reading a page's history,
its source or its editor fell back to the reader's own
language. It travels on the row of activities and on the
links the page draws.
- ✓ Reverting goes back to the
history, in the locale it was read in. A revert
wrote the old words into the reader's locale rather than the
version's. The way out afterwards led to the group's talk
rather than the history.
- ✓ A locale is named by its
language wherever it is shown. The history and the
message about a group having no pages gave the tag. They now
read as the edit page has always read.
- ✓ A page's history carries a
way back to it. Reading the history left no way out
but the browser's own back. A close mark stands beside the
button that asks for a difference.
- ✓ The scripts are named for
what they hold. help.js was mostly a reader of wiki
markup. The reading now lives in wiki_parser.js, the preview
machinery in editor.js, and markdown_parser.js reads markdown.
Everything that includes or names them moved with them.
- ✓ A message naming a character
set the machine has never heard of no longer stops the mail
server. A subject written in windows-1250 was handed
straight to the converter, which raises an error rather than
reporting a failure. The conversion is attempted and any error
caught, another way is tried, and text that cannot be converted
is kept as it came.
- ✓ A pull of the live repository
completes. Cloning worked while pulling did not, in a
different way each round. A pull now finishes against the repository
the site itself is served from. Each fault was a way of doing too
much at once. A whole pack in memory, a whole history walked, a
whole chain of differences held. The parts below are those, oldest
first.
- ✓ Serving a pull no longer holds
the whole site. One pull ran for two minutes with
nothing else answered. Building a pack walks history and works
out differences, a long stretch with no waiting in it. The
service runs inside a fiber and hands the loop back between
objects. A task carries its own running-time limit, since the
page-rendering one cut the pull short.
- ✓ A pack is built into a file
rather than in memory. Holding every object exhausted
two gigabytes on a repository of any size. The reply is built
into a scratch file that spills to disk. The server drains it a
piece at a time. A failure part way through is now an error
the other side can see.
- ✓ A repository holding a large
file can be cloned. An object was refused past
sixty-four megabytes, so a project holding a larger one could
not be cloned. The ceiling is five hundred and twelve megabytes
now. A very large object is sent whole, since comparing two such
objects holds both.
- ✓ A long chain of differences is
read one step at a time. A chain ran to a thousand
steps, each holding its difference while the version below was
read. The version below is read first and the difference
unpacked after. The chain is followed no further than git itself
writes.
- ✓ A client's lines are read only
as far as they go. Reading carried on past the last
line into what followed, which in a push is the pack. Those
bytes went to a hexadecimal reading that took whichever
characters were valid. Anything that is not a length now ends
the reading.
- ✓ A pull stops where the two
sides' histories meet. Only the commit a client named
was marked as reached, not the ones before it. So a commit off
the path being walked stopped nothing. The whole repository was
gathered for a pull of a few objects. The client's own history
is walked first, commits alone, costing a fraction of a
millisecond each. On a branch that left the trunk forty commits
back, the walk now gathers what git names.
- ✓ A request and a failed reply
both say what they were. A build that failed left no
headers, no body and nothing in any log. Several rounds of
chasing it had no evidence to work from. A switch records each
request's length, first bytes and encoding, and what was built
in answer. A build that throws is recorded with the object it
failed on and answered with the reason.
- ✓ The search bar and the results
share the reading column's measure. The bar stood twice as
tall as it should on a wide window. It and the count of results ran
to the window's edge. Both now end where the reading column ends.
That measure is named once and shared. Right edges line up rather
than drifting apart as a window widens.
- ✓ The search bar beside the logo
is one line again. Its field had a width of its own,
leaving too little room beside it. The two buttons were sent
onto a second line. The field takes whatever room is left now,
which keeps the bar one line at any width. The logo and the bar
sit side by side as a row. Before, one was lifted by a fixed
amount to appear beside the other.
- ✓ The panel beside the results
moves into the column when it cannot fit. Kept beside
the results it lay over the advertisement, the count and the
results themselves. Below the width where column and panel
cannot both fit, the panel is carried into the column. The one
panel is moved rather than a second drawn, so the page says each
thing once.
- ⚑ A group sets a theme,
header and footer for all its pages. Each page had to be
set by hand, so a group of any size drifted apart. A group now
holds all three for a page that sets none of its own, and can say
whether a page may set its own at all; where it may not, the
controls are not offered. Its settings screen is grouped into
Organization, Membership, Appearance, Feeds and Wiki, each with its
own help.
- ⚑ A writer can keep several
lines together where only one line was allowed. The
meaning beside a term in a definition list ended at its line, so a
list or a second paragraph could not go inside one. A same-unit
mark now holds as many lines as are wanted. Markdown gained
definition lists at the same time, having had none.
- ⚑ A writer can put in any
markup without remembering how it is spelt. The row of
marks above the writing area covers what is reached for most, and
everything else had to be typed from memory or looked up on the
syntax page. A mark beside the search one opens a list of the rest,
and choosing a line puts that markup in where the writer was, with
an example in each part it takes. The list scrolls, so it does not
push the writing area off the screen.